/**
 * 
 */
package adnotatio.rdf;

import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.Iterator;

import junit.framework.TestCase;

import org.w3c.dom.Document;

import adnotatio.common.xml.XMLDocument;
import adnotatio.server.DOMUtil;
import adnotatio.server.xml.dom.DomXmlDocument;

class ModelSerializer implements BasicVocabulary {

    private int fDepth;

    private boolean fEol;

    /**
     * @param resource
     * @return
     */
    private String getResourceType(Resource resource) {
        PropertyValue typeValue = resource.getValue(BasicVocabulary.RDF_TYPE);
        String type = null;
        if (typeValue != null) {
            Object value = typeValue.getValue();
            type = value.toString();
        }
        if (type == null) {
            type = "rdf:Description";
        }
        return type;
    }

    /**
     * @param string
     */
    private void print(String string) {
        fEol = false;
        System.out.print(string);
    }

    private void printContainer(Container container) {
        printEol();
        ID id = container.getID();
        printShift();
        println("<rdf:Seq>");
        fDepth++;
        int len = container.getSize();
        for (int i = 0; i < len; i++) {
            PropertyValue value = container.getValue(i);
            if (value instanceof Reference) {
                Reference ref = (Reference) value;
                ID refId = ref.getID();
                printEol();
                printShift();
                println("<rdf:li rdf:resource='" + refId + "' />");
            } else {
                printEol();
                printShift();
                print("<rdf:li>");
                printValue(value);
                printEol();
                printShift();
                println("</rdf:li>");
            }
        }
        fDepth--;
        printEol();
        printShift();
        println("</rdf:Seq>");
        printShift();
    }

    private void printEol() {
        if (!fEol) {
            System.out.println();
        }
        fEol = true;
    }

    /**
     * @param string
     */
    private void println(String string) {
        print(string);
        printEol();
    }

    public void printModel(Model model) {
        printShift();
        println("<rdf:RDF xmlns:rdf='" + NS_RDF + "'>");
        printEol();
        fDepth++;
        Iterator iterator = model.getResourceIterator();
        while (iterator.hasNext()) {
            Resource resource = (Resource) iterator.next();
            printResource(resource);
        }
        fDepth--;
        printShift();
        println("</rdf:RDF>");
    }

    private void printProperty(ID propertyID, PropertyValue value) {
        printShift();
        if (value instanceof Reference) {
            Reference ref = (Reference) value;
            println("<"
                + propertyID.getName()
                + " rdf:resource='"
                + ref.getID()
                + "' />");
        } else {
            print("<" + propertyID.getName() + ">");
            printValue(value);
            println("</" + propertyID.getName() + ">");
        }
    }

    private void printResource(Resource resource) {
        if (resource == null) {
            return;
        }
        ID id = resource.getID();
        printShift();
        String type = getResourceType(resource);
        println("<" + type + ">");
        println("<rdf:Description rdf:about='" + id + "'>");
        fDepth++;
        ID[] properties = resource.getPropertyIDs();
        for (int i = 0; i < properties.length; i++) {
            ID propertyID = properties[i];
            if (!RDF_TYPE.equals(propertyID)) {
                PropertyValue value = resource.getValue(propertyID);
                printProperty(propertyID, value);
            }
        }
        fDepth--;
        printShift();
        println("</" + type + ">");
    }

    /**
     * 
     */
    private void printShift() {
        for (int i = 0; i < fDepth; i++) {
            print("    ");
        }
    }

    private void printValue(PropertyValue value) {
        if (value instanceof Container) {
            fDepth++;
            printContainer((Container) value);
            fDepth--;
        } else {
            print(value.toString());
        }
    }
}

/**
 * @author kotelnikovе
 */
public class RDFParserTest extends TestCase {

    /**
     * @param name
     */
    public RDFParserTest(String name) {
        super(name);
    }

    private XMLDocument getDocument(Reader reader) throws Exception {
        Document dom = DOMUtil.readXML(reader);
        return new DomXmlDocument(dom);
    }

    private XMLDocument getDocument(String xml) throws Exception {
        return getDocument(new StringReader(xml));
    }

    private XMLDocument getDocumentFromResource(String name) throws Exception {
        Class<?> cls = getClass();
        String path = cls.getPackage().getName();
        path = "/" + path.replace('.', '/') + "/";
        path += name;
        InputStream input = cls.getResourceAsStream(path);
        Document dom = DOMUtil.readXML(input);
        return new DomXmlDocument(dom);
    }

    public void test() throws Exception {
        XMLDocument doc = getDocumentFromResource("feed-nuig.rdf");
        assertNotNull(doc);

        RDFParser parser = new RDFParser();
        Model model = parser.load(doc);
        assertNotNull(model);

        ModelSerializer s = new ModelSerializer();
        s.printModel(model);
    }
}
